package manager

import (
	"context"
	"fmt"
	"github.com/tianjigames/fairy/constants"
	"github.com/tianjigames/fairy/model"
	"github.com/tianjigames/fairy/protos"
	"github.com/topfreegames/pitaya"
	"github.com/topfreegames/pitaya/cluster"
	"github.com/topfreegames/pitaya/logger"
	"math/rand"
	"sync"
	"time"
)

var (
	GameServerPlayerManager *gameServerPlayerManager
	gameServerPlayerManagerOnce sync.Once
	logoutCommonMsg = &protos.WLPlayerLogout{}
)


/**
游戏玩家管理器
 */
type gameServerPlayerManager struct {
	BaseManager
	allPlayerOnGameServerMap  map[string]*model.PlayerInfo //游戏服务器上所有玩家列表
	onlineIdMap map[int]int64 //在线玩家列表
	onlineMap map[int64]*model.PlayerInfo
}

func NewGameServerPlayerManager() *gameServerPlayerManager {
	gameServerPlayerManagerOnce.Do(func() {
		GameServerPlayerManager = &gameServerPlayerManager{
			allPlayerOnGameServerMap: map[string]*model.PlayerInfo{},
			onlineIdMap: map[int]int64{},
			onlineMap: map[int64]*model.PlayerInfo{},
		}
	})
	return GameServerPlayerManager
}

/**
生成玩家唯一key
*/
func (p *gameServerPlayerManager) generateAllPlayerOnGameServerMapKey(accountId int64,appId string) string {
	return fmt.Sprintf("%d%s",accountId,appId)
}

/**
获取一个在游戏服务器上玩家信息
*/
func (p *gameServerPlayerManager) GetPlayerInfoByAccount(accountId int64,appId string) *model.PlayerInfo {
	return p.allPlayerOnGameServerMap[p.generateAllPlayerOnGameServerMapKey(accountId,appId)]
}

/**
添加一个玩家信息到游戏服务器
*/
func (p *gameServerPlayerManager) AddPlayerInfo(accountId int64,appId string,info *model.PlayerInfo)  {
	logger.Log.Infof("AddPlayerInfo:accountId=%d",accountId)
	p.allPlayerOnGameServerMap[p.generateAllPlayerOnGameServerMapKey(accountId,appId)] = info
}

/**
设置某个玩家在线
 */
func (p *gameServerPlayerManager) SetPlayerOnline(accountId int64,appId string) *model.PlayerInfo {
	info,ok := p.allPlayerOnGameServerMap[p.generateAllPlayerOnGameServerMapKey(accountId,appId)]
	if ok {
		info.IsOnline = true
		p.onlineIdMap[info.PlayerId] = info.PlayerGuid
		p.onlineMap[info.PlayerGuid] = info
	}
	return info
}

/**
设置玩家下线
 */
func (p *gameServerPlayerManager) SetPlayerOffline(accountId int64,appId string) (*model.PlayerInfo,error) {
	playerInfo,ok := p.allPlayerOnGameServerMap[p.generateAllPlayerOnGameServerMapKey(accountId,appId)]
	if ok {
		//如果玩家在组队中 强制让玩家下线
		err := TeamManager.QuitTeam(playerInfo.PlayerId)
		if err != nil {
			logger.Log.Errorf("[GameServerPlayerManager]SetPlayerOffline fail,error:%s",err.Error())
			return nil,err
		}
		playerInfo.IsOnline = false
		delete(p.onlineMap,playerInfo.PlayerGuid)
		delete(p.onlineIdMap,playerInfo.PlayerId)

		svr := GetRandomServer(constants.SvTypeHall)
		if svr == nil {
			return playerInfo,nil
		}

		//让选中的服务器上的玩家登录
		err = pitaya.RPCTo(context.Background(),svr.ID,constants.PlayerLogoutRoute,&protos.LWPlayerLogoutRet{},logoutCommonMsg)
		if err != nil {
			logger.Log.Errorf("[GameServerPlayerManager]SetPlayerOffline fail,error:%s",err.Error())
			return nil,err
		}

		return playerInfo,nil
	}
	return nil,nil
}

/**
随机获取一台服务器
 */
func GetRandomServer(svType string) *cluster.Server {
	servers,_ := pitaya.GetServersByType(svType)
	if servers == nil || len(servers) == 0 {
		logger.Log.Errorf("there are now hall server available")
		return nil
	}

	srvList := make([]*cluster.Server, 0)
	s := rand.NewSource(time.Now().Unix())
	rnd := rand.New(s)
	for _, v := range servers {
		srvList = append(srvList, v)
	}
	return srvList[rnd.Intn(len(srvList))]
}

/**
通过角色id获取玩家信息对象
 */
func (p *gameServerPlayerManager) GetPlayerInfoByPlayerId(playerId int) *model.PlayerInfo {
	if v,ok := p.onlineIdMap[playerId];ok {
		if v1,ok1 := p.onlineMap[v];ok1 {
			return v1
		}
	}

	return nil
}